note
    description: "Class representing a HTTP GET request"
    author: ""
    date: "$Date$"
    revision: "$Revision$"

class
    REQUEST


create
    make

feature -- attributes

    file_type     : attached STRING_8
    is_persistent: BOOLEAN
    status        : INTEGER_32
    filename    : attached STRING
    www_directory: attached STRING
    socket         : NETWORK_STREAM_SOCKET
    message     : attached STRING
    input         : PLAIN_TEXT_FILE

feature {NONE} -- creation

    make(sock :NETWORK_STREAM_SOCKET) --initialize a request object
        do
            socket := sock;
            status := 200
            is_persistent := false
            message := ""
            file_type := ""
            filename := ""
            www_directory := "www/"
        end

    parse
        local
            query_list : LIST[STRING]
            pos : INTEGER
            arg_list : LIST[STRING]
            has_host : BOOLEAN
            version :STRING --HTTP version
            request :STRING
            filepath:STRING
            extension :STRING
            curr_str : STRING
        do
            has_host:=false
            query_list:=message.split ('%N')
            pos:=0

            from query_list.start
            until query_list.exhausted
            loop

                if pos = 0 then

                    arg_list:=query_list.item.split(' ')
                    request:=arg_list.at (1)
                    filepath:=arg_list.at (2)
                    version:= arg_list.at (3)
                else

                    arg_list:=query_list.item.split(':')
                    curr_str := arg_list.at (1)

                    if curr_str.is_case_insensitive_equal ("Host")   then

                        has_host:=true
                    else

                        if curr_str.is_case_insensitive_equal ("Connection") then

                            if arg_list.at (2).is_case_insensitive_equal ("keep-alive%R") or arg_list.at (2).is_case_insensitive_equal (" keep-alive%R") then
                                is_persistent :=true
                            else
                                is_persistent:=false
                            end
                        end
                    end
                end

                pos:= pos + 1
                query_list.forth

            end

            filename:=filepath.substring(2, filepath.count)

            if filename.count=0 then
                filename := "index.html"
            end

            filename := www_directory + filename -- files are resolved relative to this directory

            file_type:="text/html"

            if filename.has ('.') then


                extension := filename.split ('.').at (2)

                if(extension.is_equal ("html") or extension.is_equal ("txt")) then
                    file_type:="text/html"
                end

                if(extension.is_equal ("jpg") or extension.is_equal ("jpeg")) then
                    file_type:="image/jpeg"
                end
            end


            !!input.make (filename)
            if input.exists and input.is_directory then --request default file, index.html
                filename.append ("/index.html")
                !!input.make (filename)
            end

            if not input.exists then
                status := 404
            end

            if (has_host = false) then
                status:=400
            end

            if not version.is_case_insensitive_equal ("HTTP/1.1%R") then
                status:=505
            end

            if status /= 200 then
                is_persistent:=false
            end

        end

    write_string_to_socket (header : attached STRING)
    require
        notnull_socket: socket /= Void
    local
        i : INTEGER
    do
            socket.put_string (header)
    end

    write_file_to_socket
    require
        notnull_socket: socket /= Void
        notnull_file : input.exists
    local
        i : INTEGER
    do
        if input.count>0 then
            from input.start
            until input.off
            loop
                input.read_stream (4096)
                socket.put_string (input.last_string)
            end
        end
        input.close
    end

    write_response_to_socket
    do
        inspect status
        when  200 then
            write_string_to_socket(build200header(input))
            !!input.make_open_read(filename);
            write_file_to_socket

        when 404  then
            write_string_to_socket(build404response(input.name.substring (www_directory.count, input.name.count)))
        end
    end

    build200header (file : PLAIN_TEXT_FILE) : attached STRING
    local
          response : STRING
          date : DATE_TIME
          mydate : STRING

    do
        response :=""
        response.append ("HTTP/1.1 200 OK"+"%N")
        response.append ("Server: CCC_WEBSERVER"+"%N") --date
        response.append ("Content-Type: "+file_type+"%N")
        response.append ("Content-Length: "+file.count.out+"%N")

        create date.make_now
        mydate := date.formatted_out ("ddd, dd mmm yyyy [0]hh:[0]mi:[0]ss")
        response.append("Date:"+mydate+" GMT"+"%N")
        response.append ("%N")

        Result := response
   end



    build404response (file_name : detachable STRING) : attached STRING
    local
        response : STRING
        msg_length : INTEGER
        date : DATE_TIME
        mydate : STRING
        error_message : STRING
    do

        error_message := "<html><head><title>CCC_WEBSERVER/1.1 - Error report</title>"
        error_message.append ("<style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;}"+
         "H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;}"+
         "H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;}"+
         "BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;}"+
         "B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;}"+
         "P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}"+
         " A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head>")
        error_message.append ("<body><h1>HTTP Status 404 - "+file_name.out+"</h1>")
        error_message.append ("<HR size='1' noshade='noshade'><p><b>type</b>")
        error_message.append (" Status report</p><p><b>message</b> <u>"+file_name.out+"</u></p><p><b>description</b>")
        error_message.append ("<u>The requested resource ("+file_name.out+") is not available.</u></p>")
        error_message.append ("<HR size='1' noshade='noshade'><h3>CCC_WEBSERVER/1.1</h3></body></html>")

        response :=""
        response.append ("HTTP/1.1 404 Not Found%N")
        response.append("Server: CCC_WEBSERVER/1.1%N")
        response.append("Content-Type: text/html%N")
        response.append ("Content-Length: "+error_message.count.out+"%N")

        create date.make_now
        mydate := date.formatted_out ("ddd, dd mmm yyyy [0]hh:[0]mi:[0]ss")
        response.append("Date:"+mydate+" GMT"+"%N")
        response.append ("%N")
        response.append (error_message)

        Result := response
    end



feature -- public

    read_from_socket : BOOLEAN
    do
        socket.read_line
        from
        until socket.last_string.is_equal("%R") or socket.last_string.is_equal("")
        loop
            message.append (socket.last_string)
            message.append ("%N")
            socket.read_line
        end

        if message.is_equal("") then
            Result:= false
        else
            Result := true
        end
    end

    parse_and_serve
    do
        parse
        write_response_to_socket
    end

end
